
#pragma once
#include <new>
#include <memory>
#include "FixedSizeAllocator.h"

namespace FlameEngine
{
	template <typename T>
	class ObjectPool
	{
	public:
		ObjectPool(bool enableThreadSafe = false,uint8_t maxBlockPerMemChunk=0xff)
		{
			if(enableThreadSafe)
				m_pAllocator = new FixedSizeAllocatorThreadSafe(sizeof(T),maxBlockPerMemChunk);
			else
				m_pAllocator = new FixedSizeAllocator(sizeof(T),maxBlockPerMemChunk);
		}

		virtual ~ObjectPool()
		{
			if(m_pAllocator)
				delete m_pAllocator;
			m_pAllocator = nullptr;
		}

		template<typename... Args> 
		std::shared_ptr<T> Create(Args... params)
		{
			void* p = m_pAllocator->Allocate();
			T* newInst = new(p) T(params...);
			return std::shared_ptr<T>(newInst, 
				std::bind(&ObjectPool<T>::Release_, this, std::placeholders::_1));
		}

		//never call this function directly
		void Release_(T* p)
		{
			p->~T();
			m_pAllocator->Deallocate(p);
		}

		ObjectPool(const ObjectPool<T>&) = delete;
		ObjectPool<T>& operator= (const ObjectPool<T>&) = delete;

	protected:
		FixedSizeAllocator* m_pAllocator;
	};
}